/*
 * 础光实时操作系统PhotonRTOS -- OSEK杂项处理，
 *                         例如错误钩子相关代码
 *
 * Copyright (C) 2022 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <autosar/internal.h>

VAR(int32_t, AUTOMATIC) osek_hook_running;
VAR(OSServiceIdType, AUTOMATIC) osek_hook_service_id;
VAR(uintptr_t, AUTOMATIC) osek_hook_error_code;
VAR(uintptr_t, AUTOMATIC) osek_hook_param1;
VAR(uintptr_t, AUTOMATIC) osek_hook_param2;
VAR(uintptr_t, AUTOMATIC) osek_hook_param3;


FUNC(void, OS_CODE) os_app_error_hooks(VAR(StatusType, AUTOMATIC) code)
{
	VAR(int32_t, AUTOMATIC) i;
	VAR(CoreIdType, AUTOMATIC) core_id = GetCoreID();
	VAR(OsApplicationErrorHook, AUTOMATIC) hook;

	for (i = 0; i < AUTOSAR_NR_APPLICATION; i++) {
		hook = autosar_os_app[i].error_hook;
		if (hook != NULL && core_id == autosar_os_app[i].core_id) {
			hook(code);
		}
	}
}

static FUNC(ProtectionReturnType, OS_CODE) ProtectionHook(
	VAR(StatusType, AUTOMATIC) Fatalerror)
{
	if (Fatalerror == E_OS_STACKFAULT) {
		pr_err("[ProtectionHook] E_OS_STACKFAULT\n");
		return PRO_SHUTDOWN;
	} else if (Fatalerror == E_OS_PROTECTION_ARRIVAL) {
		pr_err("[ProtectionHook] E_OS_PROTECTION_ARRIVAL\n");
		return PRO_IGNORE;
	} else if (Fatalerror == E_OS_PROTECTION_TIME) {
		pr_err("[ProtectionHook] E_OS_PROTECTION_TIME\n");
		return PRO_IGNORE;
	} else if (Fatalerror == E_OS_PROTECTION_MEMORY){
		return PRO_TERMINATEAPPL;
	} else {
		return PRO_SHUTDOWN;
	}
}

FUNC(void, OS_CODE) osek_call_hook(void)
{
	osek_hook_running++;
	ErrorHook(osek_hook_error_code);
	os_app_error_hooks(osek_hook_error_code);
	osek_hook_running--;
}

FUNC(void, OS_CODE) autosar_protect_hook(
	VAR(StatusType, AUTOMATIC) Fatalerror)
{
	VAR(uint8_t, AUTOMATIC) result = 0;
	CONTEXT_MARK_START(ENV_PROTECTION_HOOK)
	result = ProtectionHook(Fatalerror);
	CONTEXT_MARK_END
	if (result == PRO_SHUTDOWN) {
		ShutdownOS(E_OK);
	} else if (result == PRO_TERMINATEAPPL) {
		printk("任务id: %d,出现了内存访问越界，所属的app_id: %d,将被terminate!!!!\n", current->osek_id, current->app_id);
		TerminateApplication(current->app_id, 0);
	}

}
